package handler

import (
	"io"
	"time"

	"github.com/gin-contrib/sse"
	"github.com/gin-gonic/gin"
	"github.com/lab-online/internal/report/entity"
	"github.com/lab-online/pkg/auth"
	"github.com/lab-online/pkg/logger"
	mw "github.com/lab-online/pkg/middleware"
	"github.com/lab-online/pkg/resp"
	"golang.org/x/net/context"
)

type SubscribeReportReqParams struct {
	ID uint `uri:"id" binding:"required,min=1"`
}

var SubscribeReportValidator = mw.NewValidator(func() *mw.ValidatorOptions {
	return &mw.ValidatorOptions{
		Params: &SubscribeReportReqParams{},
	}
})

// SubscribeReport 订阅实验报告
//
//	@Summary		订阅实验报告
//	@Description	SubscribeReport
//	@Tags			labs
//	@Tags			mimo
//	@Accept			json
//	@Produce		json
//	@Param			Authorization	header	string	true	"Bearer Token"
//	@Param			reportID		path	string	true	"实验报告ID"
//	@Security		bearer
//	@Router			/v1/reports/:id/subscribe [get]
func (h *Handler) SubscribeReport(c *gin.Context) {
	authEntity := c.MustGet(auth.KeyAuth).(auth.AuthEntity)
	params := c.MustGet(mw.KeyParams).(*SubscribeReportReqParams)
	reportEntity := entity.New(entity.WithID(params.ID))

	if err := resp.SetupSSE(c, 600*time.Second); err != nil {
		resp.ErrorHandler(c, err)
		return
	}

	body := make(chan []byte, 1)
	defer close(body)

	ctx, closeChannel := context.WithCancel(context.Background())
	defer closeChannel()
	if err := h.domain.SubscribeReport(ctx, authEntity, reportEntity, body); err != nil {
		c.Render(200, &sse.Event{
			Event: "close",
			Retry: 30000,
			Data:  err.Error(),
		})
		return
	}

	c.Stream(func(w io.Writer) bool {
		c.SSEvent("open", "success")
		c.Writer.Flush()

		select {
		case <-c.Request.Context().Done():
			logger.Debug("SubscribeReport client close")
		case data := <-body:
			c.SSEvent("message", string(data))
		}
		return false
	})

	c.Render(200, &sse.Event{
		Event: "close",
		Retry: 30000,
		Data:  "success",
	})
	c.Writer.Flush()
	logger.Debug("SubscribeReport close")
}
